Garbage-Collected Teardown
The book has now been published and the content of this chapter has likely changed substanstially.Please see page 500 of xUnit Test Patterns for the latest information.
How do we tear down the Test Fixture?
We let the garbage collection mechanism provided by the programming language clean up after our test.
Sketch Garbage-Collected Teardown embedded from Garbage-Collected Teardown.gif
A large part of making tests repeatable and robust is ensuring that the test fixture is torn down after each test. In languages the have garbage collection, much of the tear down can happen automatically if we refer to resources via instance variables.
How It Works
Many of the objects created during the course of our test (including both fixture setup and exercising the system under test (SUT)) are transient objects that are only kept alive as long as there is a reference to them somewhere in the program that created them. The garbage collection mechanisms of modern languages use various algorithms to detect "garbage". What is most important, though, is how they determine that something is not garbage: Any object that is reachable from any other live object or from global (i.e. static) variables will not be garbage collected.
When running our tests, the Test Automation Framework (page X) (assuming is implements Test Discovery (page X)) creates a Testcase Object (page X) for each Test Method (page X) in our Testcase Class (page X) and adds them to a Test Suite Object (page X). Whenever a new test run is started, it typically throws away the existing test suite and builds a new one (to be sure everything is fresh). By throwing away the old test suite, any objects referenced only by instance variables in those tests become candidates for garbage collection.
When To Use It
We should use Garbage-Collected Teardown whenever we possibly can as it will save us a lot of effort!
If we are using a Shared Fixture (page X), we won't be able to use Garbage-Collected Teardown unless we do something fancy to hold the reference to the fixture in such a way that it will go out of scope when our test suite has finished running.
If our programming in an environment that doesn't support garbage collection, or we have resources that don't get garbage collected automatically (things like files, sockets, records in a database), we'll need to be destroy or free them explicitly. We could use any of Inline Teardown (page X), Implicit Teardown (page X) or Automated Teardown (page X) to ensure that they are freed up properly.
Implementation Notes
Some members of the xUnit family and some IDE's go so far as to replace the classes each time the test suite is run. We may see this show up as an option called "Reload Classes" or it may be forced upon us. Be careful if we decide to take advantage of this feature to use Garbage-Collected Teardown with fixture holding class variables as we may find our tests stop running if we change IDE's or try running our tests from the command line (e.g. from "Cruise Control" or a build script.)
Motivating Example
The test below creates some in-memory objects during fixture setup and explicitly destroys them using Inline Teardown. (We could also have used Implicit Teardown in this example but that just makes it harder for readers to see what is going on.)
public void testCancel_proposed_UIT() { // setup fixture: Flight proposedFlight = createAnonymousProposedFlight(); // exercise SUT proposedFlight.cancel(); // verify outcome: try{ assertEquals( FlightState.CANCELLED, proposedFlight.getStatus()); } finally { // tearDown: proposedFlight.delete(); proposedFlight = null; } } Example UnecessaryInlineTeardown embedded from java/com/clrstream/ex6/services/test/SetupStyles.java
Because these objects are not persistent in any way, the destruction code is unnecessary and just makes the test more complicated and harder to understand.
Refactoring Notes
To convert to Garbage-Collected Teardown, we need only remove the unnecessary cleanup code. If we had been using a class variable to hold the reference to the object, we would have had to convert it to either an instance variable or a local variable both of which would have moved us from a Shared Fixture to a Fresh Fixture (page X).
Example: Garbage-Collected Teardown
In this reworked test, we are letting Garbage-Collected Teardown do the job for us.
public void testCancel_proposed_GCT() { // fixture setup: Flight mutableFlight = createAnonymousProposedFlight(); // exercise SUT mutableFlight.cancel(); // verify outcome\ assertEquals( FlightState.CANCELLED, mutableFlight.getStatus()); // tearDown: // Garbage collected when mutableFlight goes out of scope } Example GarbageCollectedTeardown embedded from java/com/clrstream/ex6/services/test/SetupStyles.java
Note how much simpler the test has become!
Copyright © 2003-2008 Gerard Meszaros all rights reserved